﻿/*
 * 作者: 谢中涞,博客园:http://www.cnblogs.com/xie-zhonglai
 * 欢迎转载,但请保留出处
 * */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Xiezl.Common.LinqEx;
namespace Xiezl.Common.EFExpressions
{
    /// <summary>
    /// 构建一个基于in表达式的查询条件
    /// </summary>
    internal class InEFExpression<T, TVal> : EFExpression<T> where T : class
    {
        /// <summary>
        /// 定义条件的实体属性
        /// </summary>
        private Expression<Func<T, TVal>> property;

        /// <summary>
        /// 值集合
        /// </summary>
        private IEnumerable<TVal> values;

        /// <summary>
        /// 实例化新的InEFExpression 查询表达式
        /// </summary>
        /// <param name="property"></param>
        /// <param name="values"></param>
        public InEFExpression(Expression<Func<T, TVal>> property, IEnumerable<TVal> values)
        {
            if (property == null)
                throw new ArgumentNullException("property");
            if (values == null || values.Count() == 0)
                throw new ArgumentNullException("values");

            this.property = property;
            this.values = values;
        }

        /// <summary>
        /// 实例化新的InEFExpression 查询表达式
        /// </summary>
        /// <param name="property"></param>
        /// <param name="vals"></param>
        public InEFExpression(Expression<Func<T, TVal>> property, params TVal[] vals)
        {
            if (property == null)
                throw new ArgumentNullException("property");
            if (vals == null || vals.Count() == 0)
                throw new ArgumentNullException("vals");

            this.property = property;
            this.values = vals;
        }

        internal override Expression Expression
        {
            get
            {
                if (_Expression == null)
                {
                    Type type = typeof(TVal);

                    object nonNullValues = values;

                    //如果是Nullable<X>类型，则转化成X类型
                    if (type.IsNullableType())
                    {
                        type = type.GetNonNullableType();

                        nonNullValues = values.Select(v => Convert.ChangeType(v, type)).ToArray();
                    }

                    var method = typeof(Enumerable).GetMethods().Single(m =>
                                   m.Name.Equals("Contains")
                                      && m.IsGenericMethod
                                      && m.GetGenericArguments().Length == 1
                                      && m.GetParameters().Length == 2).MakeGenericMethod(new Type[] { type });

                    var propertyBody = GetMemberExpression(this, property);

                    MethodCallExpression methodExp = Expression.Call(null, method, Expression.Constant(nonNullValues), propertyBody);
                    _Expression = methodExp;
                }
                return _Expression;
            }
        }
    }
}
